# encoding: utf-8
import os
import sys
import cgi
import wsgiref.handlers
from wsgiref.handlers import CGIHandler

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

import models
import functions
import cache
import options

options = functions.get_options()

class BaseRequestHandler(webapp.RequestHandler):
    """Supplies a common template generation function.
    
    When you call generate(), we augment the template variables supplied with
    the current user in the 'user' variable and the current webapp request
    in the 'request' variable.
    """
    
    def generate(self, template_name, template_values={}, page_path=None, type="main", parent=None,content_type='text/html'):
        global options
        self.user = users.get_current_user()
        values = {
            'request': self.request,
            'user': users.GetCurrentUser(),
            'login_url': users.CreateLoginURL(self.request.uri),
            'logout_url': users.CreateLogoutURL('http://' + self.request.host + '/'),
            'sidebar': functions.get_sidebar(),
            'blog_link': 'http://' + self.request.host + '/',
            'options': options
            }
        values.update(template_values)
        directory = os.path.dirname(__file__)
        path = os.path.join(directory, os.path.join('templates', template_name))
        html = template.render(path, values, debug=options.DEBUG)
        # Make cache
        if cache and options.CACHE and page_path and not self.user:
            cache.create_cache_page(parent, page_path, html, type , content_type)
        self.response.out.write(html)
    
    def main(self, message='Page not found'):
        values = {'content': '<h3>'+message+'</h3>'}
        self.generate('index.html', values)
    
    def generate_js(self, html):
        self.response.headers["Content-Type"] = "text/html"
        self.response.out.write('<script language="JavaScript">'+ html + '</script>')


class NotFound(BaseRequestHandler):
    """Not Found page"""
    def get(self, error):
        self.main()        


class FeedHandler(BaseRequestHandler):
    """Feed"""
    def get(self):
        global options
        query = models.Post.all().order('-published').filter('draft',False).filter('post_type','post')
        posts = query.fetch(limit=options.posts_per_feed)
        values = { 'feed_date': posts[0].created,
                   'posts': posts }
        self.generate('feed.html', values, os.environ['PATH_INFO'], 'feed', None,'text/xml')


class MainPageHandler(BaseRequestHandler):
    """Main page"""
    def get(self,offset=1):
        global options
        query = models.Post.all().order('-published').filter('draft',False).filter('post_type','post')
        #Pagination
        #total_count = query.count()
        total_count = functions.get_counter('global_post_counter')
        navigation = functions.navigation(offset, total_count, options.posts_per_page)
        of = (navigation['current']-1)*options.posts_per_page
        #Retrieve the posts
        posts = query.fetch(limit=options.posts_per_page,offset=of)
        values = {
              'posts': posts,
              'navigation': navigation
        }
        self.generate('main.html', values, os.environ['PATH_INFO'])


class CategoryPageHandler(BaseRequestHandler):
    """Category page"""
    def get(self, category=None, offset=1):
        if not category:
            self.main('Category not selected')
            return
        #check if exist
        category_key = 'cat_' + category.strip('/')
        cat = models.Category.get_by_key_name(category_key)
        if not cat:
            self.main('Category not found')
            return
        #get the posts of the category
        posts_query = models.Post.all().filter('categories_keys',cat).filter('draft',False).order('-published').filter('post_type','post')
        #Pagination
        #total_count = posts_query.count()        
        total_count = functions.get_counter('cat_' + cat.category_url + '_counter')
        limit = options.posts_per_page
        navigation = functions.navigation(offset, total_count, limit)
        of=(navigation['current']-1)*limit
        #Retrieve the posts
        posts = posts_query.fetch(limit=limit,offset=of)
        values = {
              'cat_name': cat.category_name,
              'posts': posts,
              'navigation': navigation
        }
        self.generate('category.html', values, os.environ['PATH_INFO'], "category", cat) 


class PostPageHandler(BaseRequestHandler):
    """Post page"""
    def get(self, type , permalink=None, offset=0):
        if not permalink:
            self.main('Post not selected')
            return
        #check if exist
        post_key = type + '_' + permalink.strip('/')
        post = models.Post.get_by_key_name(post_key)
        if not post:
            self.main('Post ' +  permalink +' not found')
            return
        values = {
              'post': post,
              'key': post.key(),
              'comments': post.comments,
              'form': models.CommentForm()
        }
        self.generate( post.post_type + '.html', values, os.environ['PATH_INFO'], "post", post)

class NewCommentHandler(BaseRequestHandler):    
    """Create a new comment"""
    def post(self):
        post_key = self.request.get('post_key')
        #retriveve the data of the form
        data = models.CommentForm(data=self.request.POST)
        msg=''
        if not data.is_valid():
            for key in data.errors.keys():
                msg += "Growl.Error({title:'%s', text: '%s'});" % (key, data.errors[key])
        elif not post_key:
            msg = "Growl.Error({title:'Error', text: 'Invalid data'});" 
        else: #all fields filled
            try:
                key = db.Key(post_key)
            except db.Error:
                msg = "Growl.Error({title:'Error', text: 'db.Error: Invalid key'});" 
            def create_comment():
                post = models.Post.get(key)
                msg = ''
                if not post: #inavild key
                    msg = "Growl.Error({title:'Error', text: 'Not Post: Invalid data'});" 
                else:
                    post.post_comment(data.clean_data, self.request.remote_addr)
                return msg
            msg += db.run_in_transaction(create_comment)
            functions.increment_counter('global_comments_counter')
        if msg:
            self.generate_js(msg)
        else:
            self.generate_js('window.location.reload();')


def Main():
    """Main method, decides to either serve cached content or call the handler."""
    #Check if requested page is cached
    user = users.GetCurrentUser()
    if not user and cache.get_cache_page(os.environ['PATH_INFO']): #Don't send cache pages to logged users
        return
    application = webapp.WSGIApplication([(r'/feed$', FeedHandler),
                                          (r'/category/(.+)/(\d+)$', CategoryPageHandler),
                                          (r'/category/(.+)', CategoryPageHandler),
                                          (r'/(post|page)/(.*)/(\d+)$', PostPageHandler),
                                          ('/comment', NewCommentHandler),
                                          (r'/(post|page)/(.*)', PostPageHandler),
                                          (r'/(\d+)$', MainPageHandler),
                                          ('/', MainPageHandler),
                                          ('/(.*)',NotFound)], debug=options.DEBUG)
    wsgiref.handlers.CGIHandler().run(application)
    return
    

if __name__ == "__main__":
  Main()

